轻量化流程图开发,比 X6 清爽太多

您所在的位置:网站首页 react 流程设计器 轻量化流程图开发,比 X6 清爽太多

轻量化流程图开发,比 X6 清爽太多

2023-05-30 11:24| 来源: 网络整理| 查看: 265

需求千千万,流程图常在

没想到多年以后,我再次遇到一个关于流程图开发的需求

以前少不更事,头铁用 GG-Editor 搞了一次流程图《在 React 项目中引入 GG-Editor 编辑可视化流程》,差点把自己给埋了

这次再遇到类似的需求,在各路大神的指点下,我选择了 React Flow 来进行开发,原因如下:

1. 相比于 jsPlumb、Antv/X6 而言,React Flow 的技术相对先进

  // 小声BB,X6 居然用到了 jquery: https://github.com/antvis/X6/blob/master/packages/x6/package.json#L70

2. 高度自定义,任何 ReactElement 都可以作为节点

3. API 真的超级简单,而且体积不大,npm 3.9 MB

 

 

一、快速上手

首先在项目中安装依赖

yarn add react-flow-renderer

注意,这里的 reat-flow 版本是 9.x,更高级的版本可能存在 API 差异,参考《Migrate to v10》

然后调用组件,传入 elements 就能渲染出一个流程图

import React from "react"; import ReactFlow from "react-flow-renderer"; const elements = [ // node { id: "1", data: { label: 'Node 1', }, position: { x: 250, y: 25 }, }, { id: "2", data: { label: 'Node 2', }, position: { x: 100, y: 125 }, }, { id: "3", data: { label: 'Node 3', }, position: { x: 250, y: 250 }, }, // edge { id: "e1-2", source: "1", target: "2" }, { id: "e2-3", source: "2", target: "3" }, ]; export default function Demo() { return ( ); }

这里的 elements 是一个包含节点 node 与连线 edge 的对象数组,他们在数据结构上有以下特点:

 

node:

- id: string  唯一标识,用于连线,必填

- position: { x: number, y: number }  定位信息,必填

- type: string  定义节点的类型,可以是 React Flow 提供的 'default' | 'input' | 'output',也可以是自定义类型

- data: {} 传入节点内的数据,根据实际的节点类型 type 传入

// 完整的配置项可以查看官网 Node Options

每一个节点都必须含有一个 id 和 postion,自定义节点必须传入 type

 

edge:

- id: string  唯一标识,必填

- source: string  连线的起始节点的 id,必填

- target: string  连线的结束节点的 id,必填

- type: string  线的类型,React Flow 提供了贝塞尔曲线 bezier、直线 straight、折线 step、带圆角的折线 smoothstep,也支持自定义连线 

// 完整的配置项可以查看官网 Edge Options

线就很好理解,只需要起点 source 和终点 target 就能完成连线

 

React Flow 还提供了两个工具方法来判断 elements 中的元素是节点还是连线

import { isNode, isEdge } from 'react-flow-renderer';

掌握了“点”与“线”的基本概念,流程图就能信手拈来

但产品经理可不会认同 React Flow 提供的默认节点类型,所以自定义节点就成了必修课

 

 

二、自定义节点

在上面介绍的 node 数据中,可以传入一个 data,这个 data 会传入节点组件中的 props

假如我们需要做一个这样的节点

可以先写按图写一个这样的 ReactNode

import React from "react"; import { isArray } from "lodash"; // data 会从 elements 数据源传入 const ListNode = ({ data }) => { const { title, list } = data || {}; return ( {title} { isArray(list) && list.map((x, i) => ( {x.name} {x.type} )) } ); }; export default Reacmo(ListNode);

通过传入的 data 就能渲染出这个节点的样式,接下来解决连线的问题

 

ReactFlow 节点的连线是通过 Handle 组件实现的

Handle 其实就是节点上的“连接点”,需要多少个连接点,就可以在组件里写多少个

它可以接收的 props 参数有:

- type:  string 连接点类型,可选值为 出口 'source' | 入口 'target',必填

- position:  string 连接点的位置,有四个可选值 'left' | 'right' | 'top' | 'bottom'

- style: object 连接点的样式,除了常见的宽高、颜色之外,还可以通过定位对 position 进行微调

- id: string 如果节点中存在存在多个 source Handle 或者多个 target Handle, 可以通过 id 来精准控制连线的起点和终点

- isConnectable: boolean 是否允许连线,可以从节点的 props 中获取

 

比如节点左上角的连接点,就可以这么写:

import React from "react"; import { Handle } from "react-flow-renderer"; const nodeBaseStyle = { background: "#0FA9CC", width: '8px', height: '8px', }; const nodeLeftTopStyle = { ...nodeBaseStyle, top: 60, }; const ListNode = ({ data, isConnectable = true }) => { return ( {/* ... */} {/* ... */} ); }; export default Reacmo(ListNode);

其他的节点也是以同样的方式添加,注意定义好 type,因为连线只能从 source 连接到 target

 

现在自定义节点已经开发好了,在使用的时候需要先注册,也就是向 传入一个 nodeTypes

然后在使用的时候,需要在 elements 中声明节点 node 的类型,以及连线 edge 的起点和终点 

const elements = [ // nodes { id: '1', // 声明节点类型 type: "list", // data 会作为 props 传给节点 data: { title: '节点-1', list: [], }, isConnectable: true, position: { x: 220, y: 65 }, }, { id: '2', // 声明节点类型 type: "list", // data 会作为 props 传给节点 data: { title: '节点-2', list: [], }, isConnectable: true, position: { x: 395, y: 260 }, }, // edges { id: "egde1-2", type: "step", // 起始节点 id source: "1", // 起点 Handle id sourceHandle: "b", // 结束节点 id target: "2", // 终点 Handle id targetHandle: "lt", }, ];

 

 

三、自定义连线

ReactFlow 提供的默认连线可以设置 label

// 图示流程图的完整示例可以参考这里

 

但 label 只能设置文本,如果要在连线中间加一个按钮,就需要自定义连线

ReactFlow edge 是通过 svg 绘制的,所以自定义连线本身也是一个

为了更方便的绘制 path,ReactFlow 提供了一些工具方法

import { // 绘制贝塞尔曲线 getBezierPath, // 绘制带圆角的折线 getSmoothStepPath, // 计算出连线的中点 getEdgeCenter, // 绘制连线末端的箭头 getMarkerEnd, } from "react-flow-renderer";

通过这些方法,就能很方便的绘制出自定义连线

const CustomEdge = ({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, borderRadius = 0, style = {}, data, arrowHeadType, markerEndId, }) => { const edgePath = getSmoothStepPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition, borderRadius, }); const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); return ( ); }

接下来是连线中点的按钮,为了在 svg 里添加 button,就需要使用 foreignObject

再通过 getEdgeCenter 获取到连线的中点,就可以绘制按钮了

const foreignObjectSize = 24; const CustomEdge = ({ id, sourceX, sourceY, targetX, targetY, }) => { const [edgeCenterX, edgeCenterY] = getEdgeCenter({ sourceX, sourceY, targetX, targetY, }); const onEdgeClick = (evt, id) => { evt.stopPropagation(); console.log(`click ${id}`); }; return ( onEdgeClick(event, id)} /> ); }

// 完整代码可以查看官方的 Edge with Button 示例

 

和节点的 nodeTypes 一样,自定义的连线也需要通过 edgeTypes 来注册

并且在 elements 中需要设置对应的连线类型

const elements = [ // node // ... // edges { id: "egde1-2", type: "link", // 使用自定义连线 source: "1", target: "2", }, ]

 

 

掌握了自定义节点和自定义连线之后,就能随意的绘制流程图了

但上面传给 的 elements 都是一开始写好的假数据

如果要开发一个真实的流程图,肯定需要数据交互,这就需要用到 ReactFlowProvider

这部分内容会在后面的文章中介绍~

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3